package org.lc.gateway.properties;

import cn.hutool.core.util.ObjUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.lc.gateway.enums.GatewayLogTypeEnum;
import org.lc.gateway.util.SchemeUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Gateway Plugin Properties
 *
 * @author dl
 */
@Slf4j
@Data
@Configuration
@ConfigurationProperties(
        prefix = "spring.cloud.gateway"
)
public class GatewayPluginProperties implements InitializingBean {

    private List<String> skipSwaggerServiceIds = List.of();

    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
    /**
     * 是否启动防Sql注入
     */
    private Boolean enabledSql = false;

    /**
     * Enable Read Request Data When use discover route by serviceId
     */
    private List<String> serviceIdSqlList = List.of();

    /**
     * Enable Read Request Data by specific path
     */
    private List<String> pathSqlList = List.of();


    /**
     * 是否启动防Xss攻击
     */
    private Boolean enabledXss = false;

    /**
     * Enable Read Request Data When use discover route by serviceId
     */
    private List<String> serviceIdXssList = List.of();

    /**
     * Enable Read Request Data by specific path
     */
    private List<String> pathXssList = List.of();


    /**
     * Enable Or Disable Log Request Detail
     */
    private Boolean enabledLog = false;

    /**
     * Enable Or Disable Read Request Data
     */
    private Boolean requestLog = false;

    /**
     * Enable Or Disable Read Response Data
     */
    private Boolean responseLog = false;

    /**
     * logType
     * all： 所有日志
     * configure:serviceId和pathList交集
     * serviceId： 只记录serviceId配置列表
     * pathList：只记录pathList配置列表
     */
    private String logType = "all";

    /**
     * Enable Read Request Data When use discover route by serviceId
     */
    private List<String> serviceIdLogList = List.of();

    /**
     * Enable Read Request Data by specific path
     */
    private List<String> pathLogList = List.of();

    @Override
    public void afterPropertiesSet() {
        log.info("Gateway plugin sqlInjection enabledSql:{}", enabledSql);
        if (!CollectionUtils.isEmpty(serviceIdSqlList)) {
            serviceIdSqlList = serviceIdSqlList.stream().map(String::toLowerCase).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(pathSqlList)) {
            pathSqlList = pathSqlList.stream().map(String::toLowerCase).collect(Collectors.toList());
        }
        log.info("Gateway plugin xssInjection enabledXss:{}", enabledXss);
        if (!CollectionUtils.isEmpty(serviceIdXssList)) {
            serviceIdXssList = serviceIdXssList.stream().map(String::toLowerCase).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(pathXssList)) {
            pathXssList = pathXssList.stream().map(String::toLowerCase).collect(Collectors.toList());
        }
        log.info("Gateway plugin logRequest  enabledLog:{}", enabledLog);
        if (!CollectionUtils.isEmpty(serviceIdLogList)) {
            serviceIdLogList = serviceIdLogList.stream().map(String::toLowerCase).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(pathLogList)) {
            pathLogList = pathLogList.stream().map(String::toLowerCase).collect(Collectors.toList());
        }
    }

    /**
     * 是否记录所有请求日志
     *
     * @return {}
     */

    public boolean isRecordAllLog() {
        return requestLog && GatewayLogTypeEnum.ALL.getType().equals(logType);
    }


    /**
     * 因为加入了SQL注入拦截，这里单独判断
     *
     * @return boolean
     */
    public boolean shouldSqlInjection(ServerWebExchange exchange) {
        return shouldInjection(exchange, enabledSql, serviceIdSqlList, pathSqlList);
    }

    /**
     * 因为加入了Xss攻击拦截，这里单独判断
     *
     * @return boolean
     */
    public boolean shouldXssInjection(ServerWebExchange exchange) {
        return shouldInjection(exchange, enabledXss, serviceIdXssList, pathXssList);
    }

    private boolean shouldInjection(ServerWebExchange exchange, boolean enabled, List<String> serviceIds, List<String> pathList) {
        /* 请求地址 */
        var path = exchange.getRequest().getPath().pathWithinApplication().value();
        if (enabled) {
            return !(serviceIds.contains(SchemeUtil.getServiceId(exchange)) &&
                    pathList.stream().anyMatch(url -> ANT_PATH_MATCHER.match(url, path)));

        }
        return false;
    }
}
